package com.bfsuol.core.redis;

import com.bfsuol.core.context.SpringUtil;
import com.bfsuol.utils.Md5Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.CollectionUtils;

import java.time.Duration;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

@Slf4j
public class MybatisRedisCache implements Cache {


    // 读写锁
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);

    //这里使用了redis缓存，使用springboot自动注入
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private String id;

    //过期时间 10分钟
    private final long expirationTime = 1000*60*10;

    public MybatisRedisCache(final String id) {
        if (id == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        }
        System.out.println("当前缓存id="+id+"===========================================");
        this.id = id;
    }

    @Override
    public String getId() {
        return this.id;
    }

    @Override
    public void putObject(Object key, Object value) {
        if (value != null) {
            log.info("put key:{}", key);
            log.info("put value:{}", value);
            System.out.println("写入缓存======================put key:{}"+key+"===========value="+value);
            String keyStr = this.getId()+Md5Utils.md5(key.toString());
            byte[] valueStr = SerializeUtil.serizlize(value);
            getRedisTemplate().opsForValue().set(keyStr , valueStr, Duration.ofMillis(expirationTime));
        }
    }

    @Override
    public Object getObject(Object key) {
        try {
            if (key != null) {
                log.info("get key:{}", key);
                String keyStr = this.getId()+Md5Utils.md5(key.toString());
                Object value = getRedisTemplate().opsForValue().get(keyStr);
                if(value==null){
                    return null;
                }
                Object valueObj = SerializeUtil.deserialize((byte[]) value);
                if (value != null) {
                    log.info("get value:{}", value);
                    System.out.println("查询缓存==============get key:"+key);
                    System.out.println("查询缓存==============get value:"+value);
                    return valueObj;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("缓存数据不存在 ");
        }
        return null;
    }

    @Override
    public Object removeObject(Object key) {
        if (key != null) {
            log.info("remove key:{}", key);
            System.out.println("缓存删除===========================remove key:"+key);
            getRedisTemplate().delete(this.getId()+Md5Utils.md5(key.toString()));
        }
        return null;
    }

    @Override
    public void clear() {
        System.out.println("清空缓存==========================================");
        Set<String> keys = getRedisTemplate().keys(  this.id + "*");
        if (!CollectionUtils.isEmpty(keys)) {
            getRedisTemplate().delete(keys);
        }
    }

    @Override
    public int getSize() {
        Long size = (Long) getRedisTemplate().execute((RedisCallback<Long>) RedisServerCommands::dbSize);
        return size.intValue();
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return this.readWriteLock;
    }

    //获取RedisTemplate,不能通过注入的方式，原因是此类是由mybatis实例化的
    private RedisTemplate getRedisTemplate() {
        //从上下文中获取redisTemplate
        RedisTemplate redisTemplate = (RedisTemplate) SpringUtil.getBeanByName("redisTemplate");
        //设置key是string类型的序列
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置hashKey是string类型的序列
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

